package arithmetic.functionTest;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;

import org.junit.jupiter.api.Test;

import com.google.common.collect.Lists;


/**
 * @author jiangfeng
 * Created on 2020-04-07
 */
public class TestFunction<A,B> {
    public String getFieldName(Fn<A, B> fn) {
        String s = Reflections.fnToFieldName(fn);
        return s;
    }


    public static <A> TestFunction<A, Object> of(Class<A> clazz) {
        return new TestFunction<A, Object>();
    }


    public static <A, B> String getField(Fn<A, B> fn) {
        return Reflections.fnToFieldName(fn);
    }

    public static <A, B> String getField2(Function<A, B> fn) {
        return Reflections.fnToFieldNames(fn);
    }

    /**
     * 传递行为  A是传入类型,b是返回类型
     * @param a
     * @param fn
     * @param <A>
     * @param <B>
     * @return
     */
    public static <A, B> String funcApply(A a,Function<A, B> fn) {
        B apply = fn.apply(a);
        System.out.println(apply);
        return Reflections.fnToFieldNames(fn);
    }

    /*public static void main(String[] args) {
        func1(3, 4, a -> a * a, b -> b * b);
        func2(4, 5, a -> a * a, b -> b * b);
    }*/

    @Test
    public void test(){
        func1(3, 4, a -> a * 2, b -> b * b);
        func2(3, 4, a -> a * 2, b -> b * b);
    }

    /**
     * method Refrence
     * 函数式:  lamda表达式,方法引用,
     *
     * 类似于函数指针
     *
     * 方法引用共分为4类
     * 1.类名::静态方法名,
     * 2.引用名(对象名)::实例方法名
     * 3.类名::实例方法名,  (要求lamda表达式第一个参数作为调用者,之后参数作为入参)
     * 4.构造方法引用:类名::new
     */
    @Test
    public void testFunctionCall(){
        List<Student> l = getData();
        l.sort(Comparator.comparing(Student::getScore));
        l.forEach(System.out::println);
        System.out.println("-----");



        // 1. 静态方法名
        List<Student> l1 = getData();
        // l0.sort((s1,s2) ->Student.compareStatic(s1,s2)); 的简写
        l1.sort(Student::compareStatic);
        l1.forEach(System.out::println);
        System.out.println("-----");

        // 2.引用(对象名)::实例方法名
        List<Student> l2 = getData();
        StudentComparetor studentComparetor = new StudentComparetor();
        //l2.sort((s1,s2) ->studentComparetor.compare(s1,s2)); //的简写
        l2.sort(studentComparetor::compare);
        l2.forEach(System.out::println);
        System.out.println("-----");


        // 3类名::实例方法名 自动将第一个参数作为调用对象,第二个参数之后作为入参
        List<Student> list = getData();
        //list.sort((s1,s2) ->s1.compare(s2)); 的简写
        list.sort(Student::compare);
        list.forEach(System.out::println);
        System.out.println("-------");


        List<String> cities = Arrays. asList("qingdao","chongqing","tianjin","beijing");
                Collections.sort(cities, (city1, city2)-> city1. compareToIgnoreCase(city2));
         cities. forEach(System.out::println);
        Collections.sort(cities, String::compareToIgnoreCase);
        cities.sort(String::compareToIgnoreCase);


    }

    public List<Student> getData(){
        return  Lists.newArrayList(
                new Student("zhangsan1", 24),
                new Student("zhangsan2", 89),
                new Student("zhangsan4", 42),
                new Student("zhangsan3", 92));
    }



    /**
     *
     */
    public static <A, B> void func1(A a, B b, Function<A, B> f1, Function<B, A> f2) {
        // 在f1执行之前先执行f2 用apply里作为入参,然后执行完了返回f1
        // 执行顺序:
        // 1. f2 入参 apply中的b
        // 2. f1 入参 上一步f2执行完的结果作为入参
        f1.getClass();
        B apply = f1.compose(f2).apply(b);
        System.out.println(apply);
    }

    public static <A, B> void func2(A a, B b, Function<A, B> f1, Function<B, A> f2) {

        //B apply = f2.andThen(f1).apply(b);
        A apply2 = f1.andThen(f2).apply(a);
        System.out.println(apply2);
    }



}
